package timehelper

import (
	"fmt"
	"longmen/server/config/global"
	"math"
	"strings"
	"time"

	"github.com/spf13/cast"
)

const (
	TIME_LAYOUT_FORMAT_1         = "2006-01-02 15:04:05"
	TIME_LAYOUT_FORMAT_2         = "20060102150405"
	TIME_LAYOUT_FORMAT_3         = "20060102"
	TIME_LAYOUT_FORMAT_4         = "2006-01-02"
	TIME_LAYOUT_FORMAT_5         = "2006-01-02 15:04:05.999"
	TIME_LAYOUT_FORMAT_6         = "2006-01-02 15:04"
	TIME_LAYOUT_FORMAT_7         = "2006/01/02 15:04:05"
	HOUR_MINTER_SECOND           = " 23:59:59"
	AFTERMOON_HOUR_MINTER_SECOND = " 11:59:59"
	DEFAULT_LOCATION_STR         = "Asia/Shanghai"
)

func LocalTimeToString(layout string) string {
	return time.Now().In(GetLocalLocation()).Format(layout)
}

func GetLocalLocation() *time.Location {
	return time.Now().Location()
}

func GetToday() time.Time {
	today, _ := time.ParseInLocation(TIME_LAYOUT_FORMAT_3, time.Now().Format(TIME_LAYOUT_FORMAT_3), time.Now().Location())
	return today
}

func GetTodayDateTime() (time.Time, time.Time) {
	timeStr := time.Now().Format("2006-01-02")
	t2, _ := time.ParseInLocation("2006-01-02", timeStr, time.Local)
	starttime := t2.AddDate(0, 0, 1)
	return t2, starttime
}

var weekdayint = [7]uint16{7, 1, 2, 3, 4, 5, 6}

func GetEvenanyWeek(year, month, day uint16) uint16 {
	var y, m, c uint16
	if month >= 3 {
		m = month
		y = year % 100
		c = year / 100
	} else {
		m = month + 12
		y = (year - 1) % 100
		c = (year - 1) / 100
	}
	week := y + (y / 4) + (c / 4) - 2*c + ((26 * (m + 1)) / 10) + day - 1
	// uint6 数据类型不会允许存储负数
	if week == 0 {
		week = 7 - (-week)%7
	} else {
		week = week % 7
	}
	which_week := int(week)
	return weekdayint[which_week]
}

/**字符串->时间对象*/
func Str2Time(formatTimeStr string) time.Time {
	timeLayout := "2006-01-02"
	loc, _ := time.LoadLocation("Local")
	theTime, _ := time.ParseInLocation(timeLayout, formatTimeStr, loc) //使用模板在对应时区转化为time.time类型
	return theTime
}

/**字符串->时间对象*/
func StrDate2Time(formatTimeStr string) (time.Time, error) {
	timeLayout := "2006-01-02"
	loc, _ := time.LoadLocation("Local")
	return time.ParseInLocation(timeLayout, formatTimeStr, loc) //使用模板在对应时区转化为time.time类型

}

func Stamp2Str(stamp int64) string {
	//时间转换的模板，golang里面只能是 "2006-01-02" （go的诞生时间）
	t := time.Unix(stamp, 0)
	if t.Year() > 1970 {
		timeTemplate1 := "2006-01-02" //常规类型
		return time.Unix(stamp, 0).Format(timeTemplate1)
	}
	return ""
}

func Stamp2FullStr(stamp int64) string {
	//时间转换的模板，golang里面只能是 "2006-01-02" （go的诞生时间）
	t := time.Unix(stamp, 0)
	if t.Year() > 1970 {
		timeTemplate1 := "2006-01-02 15:04:05" //常规类型
		return time.Unix(stamp, 0).Format(timeTemplate1)
	}
	return ""
}

/*时间戳->时间对象*/
func Stamp2Time(stamp int64) time.Time {
	stampStr := Stamp2Str(stamp)
	t, _ := StrDate2Time(stampStr)
	return t
}

// 获取一周开始结束时间戳
func GetWeekStartAndEndWithTimeStamp() (time.Time, time.Time) {
	t := time.Now().Unix()
	Year := Stamp2Time(t).Year()
	Month := Stamp2Time(t).Month()
	Day := Stamp2Time(t).Day()
	dd := GetEvenanyWeek(uint16(Year), uint16(Month), uint16(Day))
	var endtime time.Time
	var starttime time.Time
	switch dd {
	case 1:
		t2, _ := time.ParseInLocation("2006-01-02", Stamp2Time(t).Format("2006-01-02"), time.Local)
		endtime = t2.AddDate(0, 0, +7)
	case 2:
		t2, _ := time.ParseInLocation("2006-01-02", Stamp2Time(t).Format("2006-01-02"), time.Local)
		endtime = t2.AddDate(0, 0, +6)
	case 3:
		t2, _ := time.ParseInLocation("2006-01-02", Stamp2Time(t).Format("2006-01-02"), time.Local)
		endtime = t2.AddDate(0, 0, +5)
	case 4:
		t2, _ := time.ParseInLocation("2006-01-02", Stamp2Time(t).Format("2006-01-02"), time.Local)
		endtime = t2.AddDate(0, 0, +4)
	case 5:
		t2, _ := time.ParseInLocation("2006-01-02", Stamp2Time(t).Format("2006-01-02"), time.Local)
		endtime = t2.AddDate(0, 0, +3)
	case 6:
		t2, _ := time.ParseInLocation("2006-01-02", Stamp2Time(t).Format("2006-01-02"), time.Local)
		endtime = t2.AddDate(0, 0, +2)
	case 7:
		t2, _ := time.ParseInLocation("2006-01-02", Stamp2Time(t).Format("2006-01-02"), time.Local)
		endtime = t2.AddDate(0, 0, +1)
	}
	starttime = endtime.AddDate(0, 0, -7)
	return starttime, endtime
}

// INaDay2Unix 当日凌晨和晚上23:59:59的 默认传空为当前天
func INaDay2Unix(day string) (start int64, end int64) {
	if day == "" {
		day = time.Now().Format("2006-01-02")
	}
	loc, _ := time.LoadLocation("Asia/Shanghai")
	startDate := day + " 00:00:00"
	startTime, _ := time.ParseInLocation("2006-01-02 15:04:05", startDate, loc)
	//日期当天23时59分时间戳
	endDate := day + " 23:59:59"
	endTime, _ := time.ParseInLocation("2006-01-02 15:04:05", endDate, loc)
	return startTime.Unix(), endTime.Unix()
}

// 判断两个时间是不是在同一天，晚上点以前就算同一天
func TimeInSameDay(t1 time.Time, t2 time.Time) bool {
	day := t1.Format("2006-01-02")
	loc, _ := time.LoadLocation("Asia/Shanghai")
	startDate := day + " 00:00:00"
	startTime, _ := time.ParseInLocation("2006-01-02 15:04:05", startDate, loc)
	//日期当天23时59分时间戳
	endDate := day + " 23:59:59"
	endTime, _ := time.ParseInLocation("2006-01-02 15:04:05", endDate, loc)
	if t2.After(startTime) && t2.Before(endTime) {
		return true
	}
	return false
}

// string->unixTime
func StrToUnix(tm string) int64 {
	loc, _ := time.LoadLocation("Asia/Shanghai")
	var st time.Time
	var err error
	tms := strings.Split(tm, ":")
	if len(tms) == 3 {
		st, err = time.ParseInLocation("2006-01-02 15:04:05", tm, loc)
	} else if len(tms) == 2 {
		st, err = time.ParseInLocation("2006-01-02 15:04", tm, loc)
	} else if len(tms) == 1 {
		st, err = time.ParseInLocation("2006-01-02 15", tm, loc)
	} else {
		return 0
	}
	if err != nil {
		return 0
	}
	return st.Unix()
}

/**
 * @Author admin
 * @Description //时间跨度2天从昨天早上到今天晚上
 * @version: v1.8.0
 * @Date 9:52 2022/7/29
 * @Param
 * @return
 **/
func YesterdayAndToday() (int64, int64) {
	currentTime := time.Now()
	loc, _ := time.LoadLocation(DEFAULT_LOCATION_STR)
	skewingDate := currentTime.AddDate(0, 0, -1)
	yesterdayStr := skewingDate.Format(TIME_LAYOUT_FORMAT_4)
	start, _ := time.ParseInLocation(TIME_LAYOUT_FORMAT_4, yesterdayStr, loc)
	todayStr := currentTime.Format(TIME_LAYOUT_FORMAT_4)
	end, _ := time.ParseInLocation(TIME_LAYOUT_FORMAT_1, todayStr+HOUR_MINTER_SECOND, loc)
	return start.Unix(), end.Unix()
}

/**
 * @Author admin
 * @Description
 * @version: v1.8.0
 * @Date 9:52 2022/7/29
 * @Param
 * @return
 **/
func TodayAndTomorrow() (int64, int64) {
	currentTime := time.Now()
	loc, _ := time.LoadLocation(DEFAULT_LOCATION_STR)
	todayStr := currentTime.Format(TIME_LAYOUT_FORMAT_4)
	start, _ := time.ParseInLocation(TIME_LAYOUT_FORMAT_4, todayStr, loc)

	//skewingDate := currentTime.AddDate(0, 0, 1)
	//tomorrowStr := skewingDate.Format(TIME_LAYOUT_FORMAT_4)
	end, _ := time.ParseInLocation(TIME_LAYOUT_FORMAT_1, todayStr+HOUR_MINTER_SECOND, loc)
	return start.Unix(), end.Unix()
}

func GetTimeDifference() time.Duration {
	nowTime := time.Now()
	// 当天秒级时间戳
	nowTimeStamp := nowTime.Unix()

	nowTimeStr := nowTime.Format("2006-01-02")

	//使用Parse 默认获取为UTC时区 需要获取本地时区 所以使用ParseInLocation
	t2, _ := time.ParseInLocation("2006-01-02", nowTimeStr, time.Local)
	// 第二天零点时间戳
	towTimeStamp := t2.AddDate(0, 0, 1).Unix()

	return time.Duration(towTimeStamp-nowTimeStamp) * time.Second
}

// GetTimeStamp 获取时间戳
func GetTimeStamp(category uint8) int64 {
	//时区应当统一配置
	t := time.Now()
	loc, err := time.LoadLocation(DEFAULT_LOCATION_STR)
	if err != nil {
		global.Log.Errorf("GetTimeStamp err:%v", err)
		return time.Now().Unix()
	}
	now := t.In(loc)
	switch category {
	case 1: //秒
		return now.Unix()
	case 2: //毫秒
		return now.UnixMilli()
	case 3: //微秒
		return now.UnixMicro()
	case 4: //纳秒
		return now.UnixNano()
	default:
		return now.Unix()
	}
}

/**
 * @Author admin
 * @Description //时间向前或向后移x天
 * @version: v1.8.0
 * @Date 14:56 2022/7/22
 * @Param
 * @return
 **/
func DateSkewing(days int) int64 {
	currentTime := time.Now()
	skewingDate := currentTime.AddDate(0, 0, days)
	nowTimeStr := skewingDate.Format("2006-01-02")
	t2, _ := time.ParseInLocation("2006-01-02", nowTimeStr, time.Local)
	return t2.Unix()
}

func GetLeftDays(et_tamp int64) uint32 {
	st_tamp := GetTimeStamp(1) //得到当前以秒为单位的timeStamp
	if st_tamp >= et_tamp {    //start 和end的距离
		return 0
	}
	// 按秒算
	left_day := (et_tamp - st_tamp) / 86400
	return uint32(left_day + 1) //只要是多1秒就算1天
}

/**
 * @Author admin
 * @Description //时间向前或向后移x天
 * @version: v1.8.0
 * @Date 14:56 2022/7/22
 * @Param
 * @return
 **/
func DateSkewingEnd(days int) int64 {

	currentTime := time.Now()
	loc, _ := time.LoadLocation(DEFAULT_LOCATION_STR)
	skewingDate := currentTime.AddDate(0, 0, days)
	nowTimeStr := skewingDate.Format(TIME_LAYOUT_FORMAT_4)
	end, _ := time.ParseInLocation(TIME_LAYOUT_FORMAT_1, nowTimeStr+HOUR_MINTER_SECOND, loc)
	return end.Unix()
}

/**
 * @Author admin
 * @Description //时间向前或向后移x天
 * @version: v1.8.0
 * @Date 14:56 2022/7/22
 * @Param
 * @return
 **/
func DateSkewingSecond(second int) string {
	currentTime := time.Now()

	skewingDate := currentTime.Add(time.Second * time.Duration(second))
	return skewingDate.Format(TIME_LAYOUT_FORMAT_2)
}

/**
 * @Author admin
 * @Description //腊秒转字符串
 * @version: v1.8.0
 * @Date 10:39 2022/8/19
 * @Param
 * @return
 **/
func GetTimeNanoToStr() string {
	return cast.ToString(time.Now().UnixNano())
}

/**
 * @Author willi
 * @Description //TODO
 * @Date 14:45 2022/9/5
 * @Param
 * @return
 **/
func GetDateOfMonthFirstAndEnd(dateStr string) (string, string) {
	date, _ := time.ParseInLocation("2006-01", dateStr, time.Local)
	endDate := GetLastDateOfMonth(date)
	return date.Format(TIME_LAYOUT_FORMAT_1), endDate.Format(TIME_LAYOUT_FORMAT_4) + HOUR_MINTER_SECOND
}

// 获取传入的时间所在月份的第一天，即某月第一天的0点。如传入time.Now(), 返回当前月份的第一天0点时间。
func GetFirstDateOfMonth(d time.Time) time.Time {
	d = d.AddDate(0, 0, -d.Day()+1)
	return GetZeroTime(d)
}

// 获取传入的时间所在月份的最后一天，即某月最后一天的0点。如传入time.Now(), 返回当前月份的最后一天0点时间。
func GetLastDateOfMonth(d time.Time) time.Time {
	return GetFirstDateOfMonth(d).AddDate(0, 1, -1)
}

// 获取某一天的0点时间
func GetZeroTime(d time.Time) time.Time {
	return time.Date(d.Year(), d.Month(), d.Day(), 0, 0, 0, 0, d.Location())
}

/**
 * @Author willi
 * @Description // 0 传入时间与今天相等，-1 比今天小，1 比今天大
 * @Date 14:46 2022/9/13
 * @Param
 * @return
 **/
func CompareDateAndNow(date string) int {
	compareDate, _ := time.ParseInLocation("2006-01-02", date, time.Local)
	todayDate, _ := time.ParseInLocation("2006-01-02", time.Now().Format("2006-01-02"), time.Local)
	switch {
	case todayDate.Equal(compareDate) == true:
		return 0
	case todayDate.After(compareDate) == true:
		return -1
	case todayDate.Before(compareDate) == true:
		return 1
	}
	return 1
}

/**
 * @Author Enzo
 * @Description 把时间秒数转化成人性化提示
 * @20221006
 * @Param
 * @return
 **/
func Time2Msg(t int64) string {
	if t <= 0 {
		return ""
	}
	d := t / (86400) //有多少天
	remain := t % (86400)
	if d > 365*3 {
		return fmt.Sprintf(",%s", global.Lang.T("permanent_ban_from_speaking"))
	}
	if d > 365 {
		return fmt.Sprintf("%s", global.Lang.T("over_a_year"))
	} else if d > 30 {
		return fmt.Sprintf("%d%s", d/30, global.Lang.T("month"))

	} else if d >= 1 {
		if remain > 86400/2 { //半天算1天
			d = d + 1
		}
		return fmt.Sprintf("%d%s", d, global.Lang.T("day"))
	}

	h := (remain) / 3600 //小时
	remain = remain % 3600
	if h > 0 {
		if remain > 3600/2 { //半小时算1小时
			h = h + 1
		}
		return fmt.Sprintf("%d%s", h, global.Lang.T("hour"))
	}
	m := remain / 60 //分钟
	if m >= 1 {
		return fmt.Sprintf("%d%s", m, global.Lang.T("min"))
	}
	return global.Lang.T("less_than_1minute")
}

/**
 * @author Jared
 * @description 获取两个时间的天数差
 * @createTime 15:38 2022/10/13
 **/
func GetDateSub(d1 time.Time, d2 time.Time) int {
	d1 = GetZeroTime(d1)
	d2 = GetZeroTime(d2)
	return int(math.Abs(d2.Sub(d1).Seconds())) / (60 * 60 * 24)
}

/*
*
检查某个时间是不是在n天前的时间
比如n==1 的时候，就检查t这个时间是不是在昨天
*/
func TimeInNDaysAgo(t time.Time, n int) bool {
	currentTime := time.Now()
	loc, _ := time.LoadLocation(DEFAULT_LOCATION_STR)
	skewingDate := currentTime.AddDate(0, 0, -n)
	dayStr := skewingDate.Format(TIME_LAYOUT_FORMAT_4) //这个是那一天的0点
	start, _ := time.ParseInLocation(TIME_LAYOUT_FORMAT_4, dayStr, loc)
	end, _ := time.ParseInLocation(TIME_LAYOUT_FORMAT_1, dayStr+HOUR_MINTER_SECOND, loc) //那一天的23:59:59
	if (t.After(start) || t == start) && (t.Before(end) || t == end) {
		return true
	}
	return false
}

// 获得当天凌晨的时间戳
func Midnight() int64 {
	// 获取当前时间
	now := time.Now()
	// 将时间戳设为当天凌晨
	midnight := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
	return midnight.Unix()
}
